/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#include "simodo/utility/generateDotFile.h"
#include "simodo/utility/common_functions.h"

// #include "simodo/sbl/OperationCode.h"

#include "simodo/inout/convert/functions.h"

#include <iostream>
#include <fstream>

namespace
{
    void generateDotBoxes(const simodo::ast::Node & node, std::ostream & dot, const std::map<simodo::ast::OperationCode,std::string> &excluded_nodes)
    {
        for(const simodo::ast::Node & n : node.branches())
        {
            std::string substitute_text;

            if (auto it=excluded_nodes.find(n.operation()); it != excluded_nodes.end()) {
                substitute_text = it->second;

                if (substitute_text.empty())
                    continue;
            }

            std::string text = simodo::inout::toU8(n.token().token());

            simodo::utility::replaceAll(text, "\\", "\\\\");
            simodo::utility::replaceAll(text, "{", "\\{");
            simodo::utility::replaceAll(text, "}", "\\}");
            simodo::utility::replaceAll(text, ">", "\\>");
            simodo::utility::replaceAll(text, "<", "\\<");
            simodo::utility::replaceAll(text, "\"", "\\\"");
            simodo::utility::replaceAll(text, "|", "\\|");

            dot << "\tS" << &n
                   ;

            if (!substitute_text.empty())
                dot << "[fillcolor=\"gold\", label=\"{"
                    << substitute_text
                       ;
            else 
                dot << ((n.operation() == 0 || n.operation() >= 1000) 
                       ? "[label=\"{"
                       : "[fillcolor=\"lightgreen\", label=\"{")
                    << simodo::inout::toU8(n.host())
                    << " | " << n.operation()
                    << " | " << text
                       ;

            dot << "}\"]"
                << ";" << std::endl;

            generateDotBoxes(n, dot, excluded_nodes);
        }
    }

    void generateDotLines(const simodo::ast::Node & node, std::ostream & dot, const std::map<simodo::ast::OperationCode,std::string> &excluded_nodes)
    {
        int i = 1;
        for(const simodo::ast::Node & n : node.branches())
        {
            if (auto it=excluded_nodes.find(n.operation()); it != excluded_nodes.end()) {
                if (it->second.empty())
                    continue;
            }
            dot << "\tS" << &node << " -> S" << &n
                << ";" << std::endl;

            generateDotLines(n, dot, excluded_nodes);
            ++i;
        }
    }
}

namespace simodo::utility
{

void generateDotFile(const std::string & dot_file_name,
                     const ast::Node & node,
                     const std::map<ast::OperationCode,std::string> &excluded_nodes)
{
    std::ofstream dot(dot_file_name);

    if (dot.bad())
    {
        std::cout << "Не удалось записать в файл '" << dot_file_name << "'" << std::endl;
        return;
    }

    dot << "digraph \"" << dot_file_name << "\" { rankdir=\"LR\";" << std::endl;
    dot << "\t" << "node [ shape=record, fontsize=12, style=\"rounded,filled\", width=0, height=0 ];" << std::endl;
    dot << "\t" << "edge [ arrowsize=0.7 ];" << std::endl;
//        dot << "\tS" << &node << " [shape=none,margin=0,fontsize=12,fontname=Helvetica,labelfloat=false,labelloc=t,labeljust=l,label=</>]" << endl;
    dot << "\tS" << &node << " [shape=point]" << std::endl;

    generateDotBoxes(node, dot, excluded_nodes);
    generateDotLines(node, dot, excluded_nodes);

    dot << "}" << std::endl;
}

}